﻿using Hx.ADSyncPlatform.ActiveDirectory.Attributes;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
namespace Hx.ADSyncPlatform.ActiveDirectory.Access
{
    /// <summary>
    /// 组访问
    /// </summary>
    internal class GroupAccess
    {

        /// <summary>
        /// 组
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="sAMAccountName">组名称</param>
        /// <returns></returns>
        public SearchResult Single(DirectoryEntry rootEntry, string sAMAccountName)
        {
            string filter = string.Format("(&(objectcategory=Group)(sAMAccountName={0}))", sAMAccountName);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResult result = dsearcher.FindOne();
            return result;
        }


        public SearchResult SingleByDistinguishedName(DirectoryEntry rootEntry, string distinguishedName)
        {
            string filter = string.Format("(&(objectclass=Group)(distinguishedName={0}))", distinguishedName);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResult result = dsearcher.FindOne();
            return result;
        }

        /// <summary>
        /// 查询组织下的组
        /// </summary>
        /// <param name="org">所在组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <returns>返回组SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry org, SearchScope searchScope, string sAMAccountName = "")
        {
            string filter = "(objectclass=Group)";
            if (!string.IsNullOrEmpty(sAMAccountName))
            {
                filter = string.Format("(&(objectcategory=Group)(sAMAccountName={0}*))", sAMAccountName);
            }
            DirectorySearcher dsearcher = new DirectorySearcher(org, filter, null, searchScope);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 自定义查询
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="filter">LDAP查询语句</param>
        /// <param name="propertiesToLoad">需要返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pageSize">最大条数</param>
        /// <returns>返回组SearchResultCollection</returns>
        public SearchResultCollection Search(DirectoryEntry rootEntry, string filter, List<string> propertiesToLoad, SearchScope searchScope, int pageSize)
        {
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, propertiesToLoad?.ToArray(), searchScope);

            //hack:确定分页代码可用？
            if (pageSize > 0)
            {
                dsearcher.PageSize = pageSize;
            }
            SearchResultCollection searchResult = dsearcher.FindAll();
            return searchResult;
        }

        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="orgDe">组创建的组织下</param>
        /// <param name="group">组信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Create(DirectoryEntry orgDe, Group group)
        {
            group.SamAccountName = group.CN;
            if (string.IsNullOrWhiteSpace(group.CN))
                throw new ArgumentNullException($"创建组时【CN】是必要属性，不能为空。");

            var de = orgDe.Children.Add("CN=" + group.CN, "group");
            foreach (var property in group.GetType().GetProperties())
            {
                if (group.AssignedAttributes.Contains(property.Name))
                {
                    var attributes = property.GetCustomAttributes(typeof(ReadOnlyCustomAttribute), false);
                    var mustCreate = property.GetCustomAttributes(typeof(RequiredForCreateAttribute), false);
                    var v = property.GetValue(group, null);
                    //判断创建时必须的字段是否为空
                    if (mustCreate != null
                        && mustCreate.Any()
                        && v == null)
                    {
                        throw new ArgumentNullException($"创建组时【{property.Name}】是必要属性，不能为空。");
                    }

                    if (attributes == null || attributes.Length == 0)
                    {
                        if (v == null)
                        {
                            de.Properties[property.Name].Clear();
                        }
                        else
                        {
                            if (property.Name?.ToLower() == "grouptype")
                            {
                                de.Properties[property.Name].Value = ((int)property.GetValue(group)).ToString();
                            }
                            else
                            {
                                de.Properties[property.Name].Value = v;
                            }

                        }

                    }
                }
            }
            de.CommitChanges();
            return true;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="groupDe">源组</param>
        /// <param name="group">组新信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Update(DirectoryEntry groupDe, Group group)
        {
            foreach (var property in group.GetType().GetProperties())
            {
                if (group.AssignedAttributes.Contains(property.Name))
                {
                    var attributes = property.GetCustomAttributes(typeof(IgnoreUpdateAttribute), false);
                    var v = property.GetValue(group, null);
                    if ((attributes == null || !attributes.Any()) && v != null)
                    {
                        if (v == null)
                        {
                            groupDe.Properties[property.Name].Clear();
                        }
                        else
                        {
                            if (property.Name?.ToLower() == "grouptype")
                            {
                                groupDe.Properties[property.Name].Value = ((int)property.GetValue(group)).ToString();
                            }
                            else
                            {
                                groupDe.Properties[property.Name].Value = v;
                            }
                        }
                    }
                }
            }
            groupDe.CommitChanges();
            return true;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="groupDe">组</param>
        /// <returns>成功True，失败False</returns>
        public bool Delete(DirectoryEntry groupDe)
        {
            groupDe.DeleteTree();
            return true;
        }

        /// <summary>
        /// 移动
        /// </summary>
        /// <param name="orgDe">移动的目标组织</param>
        /// <param name="groupDe">需要移动的组</param>
        /// <returns>成功True，失败False</returns>
        public bool Move(DirectoryEntry orgDe, DirectoryEntry groupDe)
        {
            groupDe.MoveTo(orgDe);
            return true;
        }

        /// <summary>
        /// 添加组成员
        /// </summary>
        /// <param name="groupDe">需要添加成员的组</param>
        /// <param name="members">需要添加的成员</param>
        /// <returns>成功True，失败False</returns>
        public bool AddMember(DirectoryEntry groupDe, List<string> members)
        {
            foreach (var member in members)
            {
                if (!groupDe.Properties["member"].Contains(member))
                {
                    groupDe.Properties["member"].Add(member);
                }
            }
            groupDe.CommitChanges();
            return true;
        }

        /// <summary>
        /// 删除组成员
        /// </summary>
        /// <param name="groupDe">需要删除成员的组</param>
        /// <param name="members">需要删除的成员</param>
        /// <returns>成功True，失败False</returns>
        public bool RemoveMember(DirectoryEntry groupDe, List<string> members)
        {
            foreach (var member in members)
            {
                groupDe.Properties["member"].Remove(member);
            }
            groupDe.CommitChanges();
            return true;
        }

        /// <summary>
        /// 清除组成员
        /// </summary>
        /// <param name="groupDe"></param>
        /// <returns></returns>
        public bool ClearMember(DirectoryEntry groupDe)
        {
            groupDe.Properties["member"].Clear();
            groupDe.CommitChanges();
            return true;
        }
    }
}
